﻿using System;
using System.Collections.Generic;
using System.ComponentModel.Composition;
using System.Data;
using System.Linq;
using System.Transactions;
using System.Web.Hosting;
using System.Data.Objects;

namespace PAMD.Database.Services
{
    [Export(typeof(AccountService))]
    [PartCreationPolicy(CreationPolicy.Shared)]
    public class AccountService
    {
        readonly PAMDEntities _contexts = new PAMDEntities();

        public AccountService()
        {
            _contexts.ListingFeatures.MergeOption = MergeOption.OverwriteChanges;
            _contexts.ListingPhotoes.MergeOption = MergeOption.OverwriteChanges;
            _contexts.ListingPrices.MergeOption = MergeOption.OverwriteChanges;
            _contexts.Listings.MergeOption = MergeOption.OverwriteChanges;
            _contexts.Occupations.MergeOption = MergeOption.OverwriteChanges;
            _contexts.Registrations.MergeOption = MergeOption.OverwriteChanges;
            _contexts.UserDetails.MergeOption = MergeOption.OverwriteChanges;
            _contexts.Addresses.MergeOption = MergeOption.OverwriteChanges;
            _contexts.Countries.MergeOption = MergeOption.OverwriteChanges;
        }

        public void AddRegistration(Registration registration, string host)
        {
            registration.Email = registration.Email.ToLower();
            registration.ActivationKey = Utils.CreateRandomnumber(6);

            _contexts.AddToRegistrations(registration);
            _contexts.SaveChanges();
            SendActivationEmail(registration, host);
        }

        public bool IsUserRegistered(string email)
        {
            var users = _contexts.UserDetails.Any(u => u.Email == email);
            var registration = _contexts.Registrations.Any(u => u.Email == email);
            return users || registration;
        }

        private bool SendActivationEmail(Registration registration, string host)
        {
            string subject = "Welcome to " + SiteConstant.CompanyName;
            Dictionary<string, string> vals = new Dictionary<string, string>();
            vals.Add("[FullName]", registration.FirstName + " " + registration.LastName);
            vals.Add("[ActivationLink]", host + "/Account/ActivateAccount?q=" + registration.ActivationKey);
            vals.Add("[email]", registration.Email);
            vals.Add("[companyname]", SiteConstant.CompanyName);

            string body = TemplateLoader.Process(HostingEnvironment.MapPath("~/EmailTemplate/ActivationEmail.xml"), vals);
            return Utils.SendMail(registration.Email, subject, body);
        }

        public bool ActivateRegisteredUser(string activationKey)
        {
            bool found = _contexts.Registrations.Any(r => r.ActivationKey == activationKey);

            if (!found)
                return false;

            Registration regDetails = _contexts.Registrations.First(r => r.ActivationKey == activationKey);

            bool canActivate = CanActivate(regDetails);
            if (!canActivate)
                return false;

            UserDetail userDetails = new UserDetail
            {
                AccountEnabled = true,
                Country = regDetails.Country,
                Email = regDetails.Email,
                Password = regDetails.Password,
                FirstName = regDetails.FirstName,
                LastName = regDetails.LastName
            };

            using (TransactionScope scope = new TransactionScope())
            {
                _contexts.AddToUserDetails(userDetails);
                _contexts.Registrations.DeleteObject(regDetails);
                _contexts.SaveChanges();
                scope.Complete();
            }
            return true;
        }

        private bool CanActivate(Registration regDetails)
        {
            return _contexts.Registrations.Any(r => r.ActivationKey == regDetails.ActivationKey);
        }

        public bool ResendActivationEmail(string email, string host)
        {
            bool found = _contexts.Registrations.Any(r => r.Email == email);

            if (!found)
                return false;

            Registration regDetails = _contexts.Registrations.First(r => r.Email == email);
            regDetails.ActivationKey = Utils.CreateRandomnumber(6);
            _contexts.SaveChanges();
            SendActivationEmail(regDetails, host);
            return true;
        }

        /// <summary>
        /// returns UserDetail or null 
        /// </summary>
        /// <param name="username"></param>
        /// <param name="password"></param>
        /// <returns></returns>
        public UserDetail Login(string username, string password)
        {
            var loweUserName = username.Trim().ToLower();
            bool found = _contexts.UserDetails.Any(u => u.Email == loweUserName && u.Password == password);
            if (found)
            {
                return _contexts.UserDetails.First(u => u.Email == loweUserName && u.Password == password);
            }
            return null;
        }

        public UserDetail GetByUserName(string username)
        {
            var loweUserName = username.Trim().ToLower();
            bool found = _contexts.UserDetails.Any(u => u.Email == loweUserName);
            if (found)
            {
                return _contexts.UserDetails.First(u => u.Email == loweUserName);
            }
            return null;
        }

        public UserDetail ResetPassword(string email, string host)
        {
            var userDetail = GetByUserName(email);
            if (userDetail != null)
            {
                Cryptography cryptography = new Cryptography();
                string key = cryptography.CryptString(userDetail.Email);
                key = key.Replace("=", "_");
                Dictionary<string, string> vals = new Dictionary<string, string>();
                vals.Add("[FullName]", userDetail.FirstName + " " + userDetail.LastName);
                vals.Add("[PasswordResetLink]", host + "/Account/RecoverPassword?q=" + key);
                vals.Add("[email]", userDetail.Email);

                string subject = SiteConstant.CompanyName + " password reset.";
                string body = TemplateLoader.Process(HostingEnvironment.MapPath("~/EmailTemplate/ReSetPasswordEmail.xml"), vals);
                if (Utils.SendMail(email, subject, body))
                    return userDetail;
                return null;

            }
            return null;
        }

        public UserDetail UserDetailByResetKey(string key)
        {
            Cryptography cryptography = new Cryptography();
            string plainId = key.Replace("_", "=");
            var email = cryptography.DeCryptString(plainId);
            UserDetail userDetail = GetByUserName(email);
            if (userDetail != null)
            {
                return userDetail;
            }
            return null;
        }

        public UserDetail UpdateUserPassword(string key, string password)
        {
            Cryptography cryptography = new Cryptography();
            string plainId = key.Replace("_", "=");
            var email = cryptography.DeCryptString(plainId);
            UserDetail userDetail = GetByUserName(email);
            if (userDetail != null)
            {
                userDetail.Password = password;
                _contexts.SaveChanges();
                return userDetail;
            }
            return null;
        }

        public UserDetail ChangePassword(string email, string password)
        {
            UserDetail userDetail = GetByUserName(email);
            if (userDetail != null)
            {
                userDetail.Password = password;
                _contexts.SaveChanges();
                return userDetail;
            }
            return null;
        }
    }
}